#ifndef MESH_H
#define MESH_H

#include "Export.h"
#include "Vector3.h"
#include "Color4.h"
#include "IDrawable.h"
#include "Material.h"
#include "MeshData.h"
#include "Texture.h"
#include "IBuffer.h"
#include "VBO.h"

namespace glow
{

class SHARED Mesh : public IDrawable
{	

public :

		/**
	 *  Constructor of the Mesh
	 *\param data pointer to the data of the Mesh (default NULL)
	 *\param useVBO true if the mesh use the VBO, else false
	 *\param update_type the GLenum of the update type
	 **/
	Mesh(MeshData *data = NULL, bool useVBO = true, GLenum update_type = STREAM);
	
	/**
	 *	Delete the Mesh
	 **/
	~Mesh();
	
	/**
	 *	Set the texture in the Mesh
	 *\param filename the name of the texture file
	 **/
	void setTexture(std::string filename);

	/**
	 *	Generate the normals of the Mesh
	 *\param inv true if the normals are inversed, else false
	 **/
	void genNormals(bool inv = false);

	/* observateurs */
	/**
	 *	Get position of the Mesh
	 *\return the position of the Mesh
	 **/
	const Vector3d &getPos() const;
	/**
	 *	Get axes of the Mesh
	 *\return the axes of the Mesh
	 **/
	const Vector3d &getAxes() const;
	/**
	 *	Get scales of the Mesh
	 *\return the scale of the Mesh
	 **/
	const Vector3f &getScale() const;
	/**
	 *	Get angle of the Mesh
	 *\return the angle of the Mesh
	 **/
	float getAngle() const;

	/**
	 *	Get the table of vectices of the Mesh
	 *\return pointer to the table of vertices of the Mesh
	 **/
	const float * getVertices() const;
	/**
	 *	Get the table index of the Mesh
	 *\return pointer to the table of index of the Mesh
	 **/
	const unsigned int * getIndex() const;
	/**
	 *	Get the table of texture coordonates of the Mesh
	 *\return pointer to the table of texture coordonates of the Mesh
	 **/
	const float * getTexCoords() const;
	/**
	 *	Get the table of normals of the Mesh 
	 *\return the pointer to the table of normals of the Mesh
	 **/
	const float * getNormals() const;

	/**
	 *	Get the number of vertices of the Mesh
	 *\return the number of vertices
	 **/
	unsigned int getNbVertices() const;
	/**
	 *	Get the number of index of the Mesh
	 *\return the number of index
	 **/
	unsigned int getNbIndex() const;
	/**
	 *	Get the number of textures coordonate of the Mesh
	 *\return the number of textures coordonate
	 **/
	unsigned int getNbTexCoord() const;
	/**
	 *	Get the number of normals of the Mesh
	 *\return the number of normals
	 **/
	unsigned int getNbNormals() const;

	/* accesseurs */
	/**
	 *	Set the position of the Mesh
	 *\param pos the position of the Mesh
	 **/
	void setPos(const Vector3d &pos);
	/**
	 *	Set the angle of the Mesh
	 *\param angle the angle of rotation
	 *\param axes the axe of rotation
	 **/
	void setAngle(float angle, const Vector3d &axes);
	/**
	 *	Set the scale of the Mesh
	 *\param scale the scale applicate on the Mesh
	 **/
	void setScale(const Vector3f &scale);

	// Materials
	/**
	 *	Set the ambiant color of the Mesh
	 *\param color the ambiant color
	 **/
	void setAmbient(const Color4f &color);
	/**
	 *	Set the diffuse color of the Mesh
	 *\param color the diffuse color
	 **/
	void setDiffuse(const Color4f &color);
	/**
	 *	Set the specular color of the Mesh
	 *\param color the specular color
	 **/
	void setSpecular(const Color4f &color);
	/**
	 *	Set the shininess of the Mesh
	 *\param sh the shining value
	 **/
	void setShininess(int sh);
	
	/**
	 *	Draw the Mesh in the 3-dimention scene
	 **/
	virtual void draw() const;
	/**
	 *	Draw the normals in the 3-dimention scene
	 **/
	void drawNormals() const;

private:

	void create();
	
	void normcrossprod(float v1[3], float v2[3], float out[3]);
	void createnormal(float *v1, float *v2, float *v3,float *out);
	void addnormal(float *n, float *newnorm);
	void normalize(float v[3]);
	
	bool _useVBO;
	GLenum _update_type;
	MeshData *_data;
	Texture *_texture;
	IBuffer **_vbo;
	Material _m;
	
	Vector3d _pos, _axes;
	Vector3f _scale;
	float _angle;
	
};

}		

#endif
